home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / metasploit / tools / socketNinja.pl < prev   
Perl Script  |  2006-06-30  |  31KB  |  1,388 lines

  1. #!/usr/bin/perl
  2.  
  3. #
  4. # Yo yo, this be da socketNinja.
  5. # Alpha-2.0 release
  6. # Distribute and get a visit from tireIronNinja
  7. #
  8. # -spoon
  9.  
  10. # any place you can do a [ip:]port
  11. # you can also use 0 or 1 for ip
  12. # and 0 == 127.0.0.1 and 1 = 0.0.0.0
  13.  
  14. my $recvLength = 4096; # Herm, here for some testing reasons.
  15.  
  16.  
  17. #####     #####
  18. ##   Main    ##
  19. #####     #####
  20. use strict;
  21. use Getopt::Std;
  22. my %opts;
  23. getopts('hl:d:', \%opts); # I plan on adding more options someday
  24.  
  25. if($opts{'h'}) {
  26.   usage();
  27.   exit(0);
  28. }
  29.  
  30. my $ninja;
  31. if($opts{'d'}) {
  32.   $ninja = sN::listenNinja->new($opts{'d'});
  33. }
  34. else {
  35.   $ninja = sN::consoleNinja->new;
  36. }
  37.  
  38. if($opts{'l'}) {
  39.   $ninja->createListener($opts{'l'});
  40. }
  41.  
  42. $ninja->listenLoop;
  43.  
  44.  
  45. sub usage {
  46.   print q{
  47. socketNinja alpha-2.0
  48. -d [ip:]port : Start sN in listener mode, no console
  49. -l [ip:]port : create a listener on this port
  50. };
  51. }
  52.  
  53. #####         #####
  54. ##  SocketNinja  ##
  55. #####         #####
  56. package sN::socketNinja;
  57. use strict;
  58. use IO::Select;
  59.  
  60. sub new {
  61.   my $self = bless(
  62.     {
  63.       __PACKAGE__.'selector' => IO::Select->new,
  64.       __PACKAGE__.'listeners' => [ ],
  65.       __PACKAGE__.'config' => { },
  66.     }, shift);
  67.   $self->_config($self->readConfig);
  68.   return($self);
  69. }
  70.  
  71. sub _selector {
  72.   my $self = shift;
  73.   $self->{__PACKAGE__.'selector'} = shift if(@_);
  74.   return($self->{__PACKAGE__.'selector'});
  75. }
  76. sub _listeners {
  77.   my $self = shift;
  78.   $self->{__PACKAGE__.'listeners'} = shift if(@_);
  79.   return($self->{__PACKAGE__.'listeners'});
  80. }
  81. sub _config {
  82.   my $self = shift;
  83.   $self->{__PACKAGE__.'config'} = shift if(@_);
  84.   return($self->{__PACKAGE__.'config'});
  85. }
  86.  
  87.  
  88. sub getListeners {
  89.   my $self = shift;
  90.   return(@{$self->_listeners});
  91. }
  92. sub addListener {
  93.   my $self = shift;
  94.   foreach (@_) {
  95.     push(@{$self->_listeners}, $_);
  96.     $_->setName($self->lSock($_));
  97.     $_->setParent($self);
  98.     $self->_selector->add($_);
  99.   }
  100. }
  101. sub connectServerListener {
  102.   my $self = shift;
  103.   my $i = 0;
  104.   foreach ($self->getListeners) {
  105.     return($i) if($_->getName eq 'connectServers');
  106.     $i++;
  107.   }
  108.   return(-1);
  109. }
  110. sub connectClientAttachedListener {
  111.   my $self = shift;
  112.   my $listenerIndex = shift;
  113.   my $serverIndex = shift;
  114.   my $i = 0;
  115. #fixme
  116. #  print "- $listenerIndex - $serverIndex -\n";
  117.   foreach ($self->_listeners->[$listenerIndex]->_servers->[$serverIndex]->getAttachedListeners) { #fixme
  118.     return($i) if($_->getName eq 'connectClients');
  119.     $i++;
  120.   }
  121.   return(-1);
  122. }
  123.  
  124. sub removeListener {
  125.   my $self = shift;
  126.   my $listener = shift;
  127.   for(my $i = 0; $i < @{$self->_listeners}; $i++) {
  128.     splice(@{$self->_listeners}, $i, 1) if($self->_listeners->[$i] == $listener);
  129.   }
  130.   $self->_selector->remove($listener);
  131. }
  132.  
  133. sub getConfig {
  134.   my $self = shift;
  135.   return(%{$self->_config});
  136. }
  137.  
  138. sub createListener {
  139.   my $self = shift;
  140.   my ($addr, $port) = $self->parseConn(shift, 1); # default to public
  141.   my $listener = sN::listener->new(
  142.     LocalPort => $port,
  143.     LocalAddr => $addr,
  144.     Proto => 'tcp',
  145.     ReuseAddr => 1,
  146.     Listen => 5,
  147.   );
  148.   if(!$listener) {
  149.     $self->message('Failed to create listener: ' . $!);
  150.     return;
  151.   }
  152.   $self->addListener($listener);
  153.   $self->message('Created listener ' . $listener->getName);
  154. }
  155.  
  156. sub addAttachedListener {
  157.   my $self = shift;
  158.   my $listenerIndex = shift;
  159.   my $serverIndex = shift;
  160.   my $listenSock = shift;
  161.   $listenSock->setName($self->lSock($listenSock));
  162.   $self->_listeners->[$listenerIndex]->_servers->[$serverIndex]->addAttachedListener($listenSock); #fixme
  163.   $self->_selector->add($listenSock);
  164. }
  165.  
  166. sub createRandomAttachedListener {
  167.   my $self = shift;
  168.   my $listenerIndex = shift;
  169.   my $serverIndex = shift;
  170.   $self->addAttachedListener($listenerIndex, $serverIndex, $self->makeRandomAttachedListener);
  171. }
  172. sub createCustomAttachedListener {
  173.   my $self = shift;
  174.   my $listenerIndex = shift;
  175.   my $serverIndex = shift;
  176.   my $conn = shift;
  177.   my $attachedListener = $self->makeCustomAttachedListener($self->parseConn($conn));
  178.   return if(!$attachedListener);
  179.  
  180.   $self->addAttachedListener($listenerIndex, $serverIndex, $attachedListener);
  181. }
  182.  
  183. sub makeRandomAttachedListener {
  184.   my $self = shift;
  185.   my $listenPort;
  186.   my $listenSock;
  187.   do {
  188.     $listenPort = int(rand(10000)) + 2000;
  189.     $listenSock = sN::attachedListener->new(
  190.       LocalAddr => '127.0.0.1',
  191.       LocalPort => $listenPort,
  192.       Proto => 'tcp',
  193.       ReuseAddr => 1,
  194.       Listen => 5,
  195.     );
  196.     if(!$listenSock) {
  197.       $self->debug("Socket no good: " . $! . ", trying again");
  198.     }
  199.     else {
  200.       $self->message('New listener (' . $listenSock->fileno . ") bound to 127.0.0.1:$listenPort");
  201.     }
  202.   } while(!$listenSock);
  203.  
  204.   return($listenSock);
  205. }
  206. sub makeCustomAttachedListener {
  207.   my $self = shift;
  208.   my $addr = shift;
  209.   my $port = shift;
  210.   my $listenSock;
  211.  
  212.   $listenSock = sN::attachedListener->new(
  213.     LocalAddr => $addr,
  214.     LocalPort => $port,
  215.     Proto => 'tcp',
  216.     ReuseAddr => 1,
  217.     Listen => 5,
  218.   );
  219.   if(!$listenSock) {
  220.     $self->message('Failed to create attachedListener: ' . $!);
  221.     return;
  222.   }
  223.   else {
  224.     $self->message('New listener (' . $listenSock->fileno . ") bound to $addr:$port");
  225.   }
  226.  
  227.   return($listenSock);
  228. }
  229.  
  230. sub addConnectServer {
  231.   my $self = shift;
  232.   my $connectServer = shift;
  233.   my $listener;
  234.   if($self->connectServerListener < 0) {
  235.     $listener = sN::listener->new;
  236.     $self->addListener($listener);
  237.     $listener->setName('connectServers');
  238.   }
  239.   else {
  240.     $listener = $self->_listeners->[$self->connectServerListener];
  241.   }
  242.   $connectServer->setName($self->pSock($connectServer));
  243.   $listener->addServer($connectServer);
  244.   $self->_selector->add($connectServer);
  245.   $self->message('Added connectServer ' . $connectServer->getName);
  246. }
  247.  
  248. sub createConnectServer {
  249.   my $self = shift;
  250.   my $addr = shift;
  251.   my $port = shift;
  252.  
  253.   my $server = sN::server->new(
  254.     PeerAddr => $addr,
  255.     PeerPort => $port,
  256.     Proto => 'tcp',
  257.     Timeout => 10, # This is important, socketNinja will hang until connection is established
  258.   );
  259.   if(!$server) {
  260.     $self->message('Failed to create connectServer: ' . $!);
  261.     return;  
  262.   }
  263.   $self->addConnectServer($server);
  264. }
  265.  
  266. sub addConnectClient {
  267.   my $self = shift;
  268.   my $listenerIndex = shift;
  269.   my $serverIndex = shift;
  270.   my $connectClient = shift;
  271.   my $attachedListener;
  272.   my $ccal = $self->connectClientAttachedListener($listenerIndex, $serverIndex);
  273.   if($ccal < 0) {
  274.     $attachedListener = sN::attachedListener->new;
  275.     $self->addAttachedListener($listenerIndex, $serverIndex, $attachedListener);
  276.     $attachedListener->setName('connectClients');
  277.   }
  278.   else {
  279.     $attachedListener = $self->_listeners->[$listenerIndex]->_servers->[$serverIndex]->_attachedListeners->[$ccal]; #fixme
  280.   }
  281.   $connectClient->setName($self->pSock($connectClient));
  282.   $attachedListener->addClient($connectClient);
  283.   $self->_selector->add($connectClient);
  284.   $self->message('Added connectClient ' . $connectClient->getName);
  285. }
  286.  
  287. sub createConnectClient {
  288.   my $self = shift;
  289.   my $listenerIndex = shift;
  290.   my $serverIndex = shift;
  291.   my $addr = shift;
  292.   my $port = shift;
  293.  
  294.   my $client = sN::client->new(
  295.     PeerAddr => $addr,
  296.     PeerPort => $port,
  297.     Proto => 'tcp',
  298.     Timeout => 10, # This is important, socketNinja will hang until connection is established
  299.   );
  300.   if(!$client) {
  301.     $self->message('Failed to create connectClient: ' . $!);
  302.     return;  
  303.   }
  304.   $self->addConnectClient($listenerIndex, $serverIndex, $client);
  305. }
  306.  
  307.   
  308.  
  309. sub listenLoop {
  310.   my $self = shift;
  311.   $self->message("socketNinja started.");
  312.   while(my @ready = $self->_selector->can_read) {
  313.     foreach (@ready) {
  314.       $self->handleSocket($_);
  315.     }
  316.   }
  317. }
  318.  
  319. sub handleSocket {
  320.   my $self = shift;
  321.   my $socket = shift;
  322.   if($socket->isListener) {
  323.     $self->handleListener($socket);
  324.   }
  325.   elsif($socket->isAttachedListener) {
  326.     $self->handleAttachedListener($socket);
  327.   }
  328.   elsif($socket->isServer) {
  329.     $self->handleServer($socket);
  330.   }
  331.   elsif($socket->isClient) {
  332.     $self->handleClient($socket);
  333.   }
  334. }
  335.  
  336. sub handleListener {
  337.   my $self = shift;
  338.   my $socket = shift;
  339.   my $newSock = $socket->accept('sN::server');
  340.   $newSock->setName($self->pSock($newSock)); 
  341.   $socket->addServer($newSock);
  342.   $self->_selector->add($newSock);
  343.   $self->message('Added server ' . $newSock->getName . ' to listener ' . $socket->getName);
  344. }
  345.  
  346. sub handleAttachedListener {
  347.   my $self = shift;
  348.   my $socket = shift;
  349.   my $newSock = $socket->accept('sN::client');
  350.   $newSock->setName($self->pSock($newSock)); 
  351.   $socket->addClient($newSock);
  352.   $self->_selector->add($newSock);
  353.   $self->message('Added client ' . $newSock->getName . ' to attachedListener ' . $socket->getName);
  354. }
  355.  
  356. sub handleServer {
  357.   my $self = shift;
  358.   my $socket = shift;
  359.   my $data;
  360.   $socket->recv($data, $recvLength);
  361.   if(!length($data)) {
  362.     $self->destroyConnection($socket);
  363.     $self->message('Server connection ' . $socket->getName . ' dead');
  364.   }
  365.   else {
  366.     $socket->serverWrite($data);
  367.   }
  368. }
  369.  
  370. sub handleClient {
  371.   my $self = shift;
  372.   my $socket = shift;
  373.   my $data;
  374.   $socket->recv($data, $recvLength);
  375.   if(!length($data)) {
  376.     $self->destroyConnection($socket);
  377.  
  378.     $self->message('Client connection ' . $socket->getName . ' dead');
  379.   }
  380.   else {
  381.     $socket->getParent->getParent->clientWrite($socket, $data);
  382.   }
  383. }
  384.  
  385.  
  386. sub getServer {
  387.   my $self = shift;
  388.   my $listenerIndex = shift;
  389.   my $serverIndex = shift;
  390.   my $listener = $self->_listeners->[$listenerIndex];
  391.   return if(!$listener);
  392.   return($listener->_servers->[$serverIndex]);
  393. }
  394.  
  395. sub getAttachedListener {
  396.   my $self = shift;
  397.   my $listenerIndex = shift;
  398.   my $serverIndex = shift;
  399.   my $attachedListenerIndex = shift;
  400.  
  401.   my $listener = $self->_listeners->[$listenerIndex];
  402.   return if(!$listener);
  403.   my $server = $listener->_servers->[$serverIndex];
  404.   return if(!$server);
  405.   return($server->_attachedListeners->[$attachedListenerIndex]);
  406. }
  407.  
  408.  
  409. sub configFilename {
  410.   use File::Spec::Functions;
  411.   use File::Basename;
  412.   
  413.   my $basedir = dirname(File::Spec::Functions::rel2abs($0));
  414.   $basedir  .= $^O eq 'WIN32' ? '\\' : '/';
  415.   return($basedir . '.socketNinja');
  416. }
  417.  
  418. sub readConfig {
  419.   my $self = shift;
  420.   my $filename = $self->configFilename;
  421.  
  422.   my %defaults = (
  423.     'program' => 'Eterm -e nc -v [ip] [port]',
  424.     'program-w' => 'c:\\putty.exe -raw -P [port] [ip]',
  425.     'defaultPort' => '12345',
  426.     'superDebug' => '0',
  427.   );
  428.   
  429.   if(!-e $filename) {
  430.     return(\%defaults)
  431.   }
  432.  
  433.   my %vars;
  434.   open(INFILE, "<$filename") or return(\%defaults);
  435.   while(<INFILE>) {
  436.     chomp;
  437.     /(.*?), (.*)/;
  438.     $vars{$1} = $2;
  439.   }
  440.   close(INFILE);
  441.   return(\%vars);
  442. }
  443.  
  444. sub writeConfig {
  445.   my $self = shift;
  446.   my %vars = @_;
  447.   my $filename = $self->configFilename;
  448.   open(OUTFILE, ">$filename") or return;
  449.   foreach (keys(%vars)) {
  450.     print OUTFILE "$_, $vars{$_}\n";
  451.   }
  452.   close(OUTFILE);
  453. }
  454.  
  455. sub destroyConnection {
  456.   my $self = shift;
  457.   my $socket = shift;
  458.   my @toDestroy = $socket->getSockets;
  459.   foreach (@toDestroy) {
  460.     $self->_selector->remove($_);
  461.     $_->destroySelf;
  462.   }
  463. }
  464.  
  465. sub parseConn {
  466.   my $self = shift;
  467.   my ($port, $addr) = reverse(split(':', shift));
  468.   # defaults to private (127.0.0.1)
  469.   # 1 to default to public (0.0.0.0)
  470.   $addr = @_ ? shift : 0 if(!defined($addr)); # if 1, default to public
  471.  
  472.  
  473.   $addr = '127.0.0.1' if($addr eq 0);
  474.   $addr = '0.0.0.0' if($addr eq 1);
  475.  
  476.   return($addr, $port);
  477. }
  478. sub pSock {
  479.   my $self = shift;
  480.   my $socket = shift;
  481.   return($socket->peerhost . ':' . $socket->peerport);
  482. }
  483. sub lSock {
  484.   my $self = shift;
  485.   my $socket = shift;
  486.   return($socket->sockhost . ':' . $socket->sockport);
  487. }
  488.  
  489.  
  490.  
  491. #####          #####
  492. ##  CommandNinja  ##
  493. #####          #####
  494. package sN::commandNinja;
  495. use strict;
  496. use base 'sN::socketNinja';
  497.  
  498. sub handleData {
  499.   my $self = shift;
  500.   my $data = shift;
  501.   my($command, @args) = split(' ', $data);
  502. #fixme  $self->cprint("Got data command: $command with args(@args)\n") if($main::superDebug);
  503.   $command = $self->findCommand($command);
  504.   if(!$command) {
  505.     $self->message("Invalid command.\n");
  506.     next;
  507.   }
  508.   if($self->getCommands->{$command}[2] > @args) {
  509.     $self->launchCommand('help', $command);
  510.     next;
  511.   }
  512.   $self->launchCommand($command, @args);
  513. }
  514.  
  515.  
  516. sub getCommands {
  517.   my $self = shift;
  518.   return(
  519.     {
  520. #     HashKey/Long Name, [Short Name, Command, Least number of arguments],
  521.       'help', ['?', 'Shows the help menu', 0],
  522.       'listen', ['li', 'Create a listener', 1, '<d | [ip:]port>'],
  523.       'list', ['l', 'List connection tree', 0],
  524.       'addRandom', ['ar', 'Create a randomAttachedListener', 1, '[listener #] <server #>'],
  525.       'addCustom', ['ac', 'Create a customAttachedListener', 2, '[listener #] <server #> [ip:]<port>'],
  526.       'addServer', ['as', 'Create a connectServer', 2, '<ip> <port>'],
  527.       'addClient', ['acl', 'Create a connectClient', 2, '[listener #] [server #] <ip> <port>'],
  528.       'close', ['c', 'Close a connection', 1, '<listener #> [server #] [attachedListener #] [client #]'],
  529.       'writeConfig', ['wc', 'Write config settings out to file', 0, ''],
  530.       'showConfig', ['sc', 'Print config settings', 0, ''],
  531.       'setConfig', ['set', 'Set a config value', 2, '<key> <value>'],
  532.       'runApp', ['run', 'Launch program for attachedListener', 1, '[listener #] [server #] <attachedListener #> [altProg]'],
  533.       'quit', ['q', 'Quit', 0],
  534.     } 
  535.   );
  536. }
  537.  
  538. sub findCommand {
  539.   my $self = shift;
  540.   my $command = shift;
  541.   foreach (keys(%{$self->getCommands})) {
  542.     return($_) if($_ eq $command || $self->getCommands->{$_}[0] eq $command);
  543.   }
  544. }
  545. sub launchCommand {
  546.   my $self = shift;
  547.   my $command = shift;
  548.   my @args = @_;
  549.   no strict 'refs';  # Bah
  550.   $command = 'command_' . $command;
  551.   $self->cprint("\n");
  552.   $self->$command(@args);
  553.   $self->cprint("\n");
  554. }
  555.  
  556. ###
  557. # Commands
  558. ###
  559. sub command_list {
  560.   my $self = shift;
  561.   my $col = sN::colprint->new(1);
  562.   $self->cprint("Connection Tree\n");
  563.   $col->addRow('Listener', 'Server', 'AttachedListener', 'Client');
  564.   $col->addRow('__hr__', '__hr__', '__hr__', '__hr__');
  565.  
  566.  
  567.   # When I am less tired I will do this a better way
  568.   my $i = 0;
  569.   foreach my $listener ($self->getListeners) {
  570.     $col->addRow("$i: ".$listener->getName);
  571.     my $j = 0;
  572.     foreach my $server ($listener->getServers) {
  573.       $col->addRow('', "$j: ".$server->getName);
  574.       my $k = 0;
  575.       foreach my $attachedListener ($server->getAttachedListeners) {
  576.         $col->addRow('', '', "$k: ".$attachedListener->getName);
  577.         my $l = 0;
  578.         foreach my $client ($attachedListener->getClients) {
  579.           $col->addRow('', '', '', "$l: ".$client->getName);
  580.           $l++;
  581.         }
  582.         $k++;
  583.       }
  584.       $j++;
  585.     }
  586.     $i++;
  587.   }
  588.   $self->cprint($col->getOutput);
  589. }
  590.  
  591. sub command_addRandom {
  592.   my $self = shift;
  593.   my $serverIndex = pop; 
  594.   my $listenerIndex = @_ ? pop : 0; # If there is only 1 argument, we presume listenerIndex = 0
  595.  
  596.   if(!$self->getServer($listenerIndex, $serverIndex)) {
  597.     $self->cprint("Invalid server.\n");
  598.     return;
  599.   }
  600.   $self->createRandomAttachedListener($listenerIndex, $serverIndex);
  601. }
  602.  
  603. sub command_addCustom {
  604.   my $self = shift;
  605.   my $conn = pop;
  606.   my $serverIndex = pop;
  607.   my $listenerIndex = pop || 0;
  608.  
  609.   if(!$self->getServer($listenerIndex, $serverIndex)) {
  610.     $self->cprint("Invalid server.\n");
  611.     return;
  612.   }
  613.  
  614.   $self->createCustomAttachedListener($listenerIndex, $serverIndex, $conn);
  615. }
  616.  
  617. sub command_help {
  618.   my $self = shift;
  619.   my $command = shift;
  620.   my $col = sN::colprint->new(1);
  621.   if($command) {
  622.     $command = $self->findCommand($command);
  623.     if(!$command) {
  624.       $self->cprint("help: command not found.\n");
  625.       return;
  626.     }
  627.     my $info = $self->getCommands->{$command};
  628.     $col->addRow('command:', $command);
  629.     $col->addRow('shortcut:', $info->[0]);
  630.     $col->addRow('Description:', $info->[1]);
  631.     $col->addRow('Usage:', $info->[3]) if($info->[3]);
  632.     $self->cprint($col->getOutput);
  633.   }
  634.   else {
  635.     $self->cprint("Commands:\n");
  636.     $col->addRow('cmd', 'shortcut', 'description');
  637.     $col->addRow('__hr__', '__hr__', '__hr__');
  638.     foreach (sort(keys(%{$self->getCommands}))) {
  639.       my $info = $self->getCommands->{$_};
  640.       $col->addRow("$_:", $info->[0], $info->[1]);
  641.     }
  642.     $self->cprint($col->getOutput);
  643.   }
  644. }
  645. sub command_quit {
  646.   my $self = shift;
  647.   exit(0);
  648. }
  649. sub command_listen {
  650.   my $self = shift;
  651.   my $conn = shift;
  652.  
  653.   $conn = $self->_config->{'defaultPort'} if($conn eq 'd');
  654.   $self->createListener($conn);
  655.  
  656. }
  657. sub command_close {
  658.   my $self = shift;
  659.   my $listenerIndex = shift;
  660.   my $listener = $self->_listeners->[$listenerIndex];
  661.   if(!$listener) {
  662.     $self->message('Invalid listener.');
  663.     return;
  664.   }
  665.   if(!@_) {
  666.     $self->destroyConnection($listener);
  667.     return;
  668.   }
  669.   my $serverIndex = shift;
  670.   my $server = $listener->_servers->[$serverIndex];
  671.   if(!$server) {
  672.     $self->message('Invalid server.');
  673.     return;
  674.   }
  675.   if(!@_) {
  676.     $self->destroyConnection($server);
  677.     return;
  678.   }
  679.   my $attachedListenerIndex = shift;
  680.   my $attachedListener = $server->_attachedListeners->[$attachedListenerIndex];
  681.   if(!$attachedListener) {
  682.     $self->message('Invalid attachedListener.');
  683.     return;
  684.   }
  685.   if(!@_) {
  686.     $self->destroyConnection($attachedListener);
  687.     return;
  688.   }
  689.   my $clientIndex = shift;
  690.   my $client = $attachedListener->_clients->[$clientIndex];
  691.   if(!$client) {
  692.     $self->message('Invalid client.');
  693.     return;
  694.   }
  695.   $self->destroyConnection($client);
  696. }
  697.  
  698. sub command_writeConfig {
  699.   my $self = shift;
  700.   $self->writeConfig($self->getConfig);
  701.   $self->cprint("Wrote config.\n");
  702. }
  703. sub command_showConfig {
  704.   my $self = shift;
  705.   my %config = $self->getConfig;
  706.   my $col = sN::colprint->new(1);
  707.   $self->cprint("Config settings:\n");
  708.   $col->addRow('Key', 'Value');
  709.   $col->addRow('__hr__', '__hr__');
  710.   foreach (sort(keys(%config))) {
  711.     $col->addRow("$_", $config{$_});
  712.   }
  713.   $self->cprint($col->getOutput);
  714. }
  715. sub command_setConfig {
  716.   my $self = shift;
  717.   my $key = shift;
  718.   my $value = join(' ', @_);
  719.   $self->cprint("$key -> $value\n");
  720.   $self->_config->{$key} = $value;
  721. }
  722. sub command_runApp {
  723.   my $self = shift;
  724.  
  725. #fixme I'm still undecided on the best way of doing this
  726.   my $altProg = pop if(@_ >= 4);
  727.   my $attachedListenerIndex = pop;
  728.   my $serverIndex = pop || 0;
  729.   my $listenerIndex = pop || 0;
  730.  
  731.   $altProg = '-'.$altProg if(defined($altProg));
  732.   my $program = $self->_config->{'program'.$altProg}; #fixme
  733.   if(!defined($program)) {
  734.     $self->cprint("No program defined.\n");
  735.     return;
  736.   }
  737.   my $attachedListener = $self->getAttachedListener($listenerIndex, $serverIndex, $attachedListenerIndex);
  738.   if(!$attachedListener) {
  739.     $self->cprint("Invalid attachedListener.\n");
  740.     return;
  741.   }
  742.  
  743.   $program =~ s/\[ip\]/$attachedListener->sockhost/ge;
  744.   $program =~ s/\[port\]/$attachedListener->sockport/ge;
  745.   $self->cprint("Running: $program\n");
  746.   if(!fork()) {
  747.     exec("$program");
  748.   }
  749. }
  750. sub command_addServer {
  751.   my $self = shift;
  752.   my $addr = shift;
  753.   my $port = shift;
  754.   $self->createConnectServer($addr, $port);
  755. }
  756. sub command_addClient {
  757.   my $self = shift;
  758.   my $port = pop;
  759.   my $addr = pop;
  760.   my $serverIndex = @_ ? pop : 0;
  761.   my $listenIndex = @_ ? pop : 0;
  762.  
  763.   $self->createConnectClient($listenIndex, $serverIndex, $addr, $port);
  764. }
  765.  
  766.  
  767. #####          #####
  768. ##  ConsoleNinja  ##
  769. #####          #####
  770. package sN::consoleNinja;
  771. use strict;
  772. use base 'sN::commandNinja';
  773.  
  774. sub new {
  775.   my $class = shift;
  776.   my $self = $class->SUPER::new;
  777.   my $stdin = IO::Handle->new_from_fd(0, '<');
  778.   $self->{__PACKAGE__.'stdin'} = $stdin;
  779.   $self->_selector->add($stdin);
  780.   return($self);
  781. }
  782.  
  783. sub _stdin {
  784.   my $self = shift;
  785.   $self->{__PACKAGE__.'stdin'} = shift if(@_);
  786.   return($self->{__PACKAGE__.'stdin'});
  787. }
  788.  
  789. sub handleSocket {
  790.   my $self = shift;
  791.   my $socket = shift;
  792.   if($socket == $self->_stdin) {
  793.     $self->handleStdin($socket);
  794.   }
  795.   else {
  796.     $self->SUPER::handleSocket($socket);
  797.   }
  798. }
  799.  
  800. sub handleStdin {
  801.   my $self = shift;
  802.   my $socket = shift;
  803.   my $data = <$socket>;
  804.   $self->handleData($data);
  805. }
  806.  
  807. sub message {
  808.   my $self = shift;
  809.   print "* ", shift, "\n";
  810. }
  811.  
  812. sub cprint {
  813.   my $self = shift;
  814.   print shift;
  815. }
  816.  
  817.  
  818. #####          #####
  819. ##  ListenNinja  ##
  820. #####          #####
  821. package sN::listenNinja;
  822. use strict;
  823. use base 'sN::commandNinja';
  824.  
  825. #
  826. # This should all be rewritten, it is ugly
  827. # It should basically be a server (the class)
  828. #
  829.  
  830. sub new {
  831.   my $class = shift;
  832.   my ($addr, $port) = $class->parseConn(shift); # default to private
  833.  
  834.   my $listener = sN::listener->new(
  835.     LocalPort => $port,
  836.     LocalAddr => $addr,
  837.     Proto => 'tcp',
  838.     ReuseAddr => 1,
  839.     Listen => 5,
  840.   );
  841.   if(!$listener) {
  842.     print STDERR "Could not listen: $!\n";
  843.     exit(1);
  844.   }
  845.   
  846.   my $self = $class->SUPER::new;
  847.  
  848.   $self->{__PACKAGE__.'listener'} = $listener;
  849.   $self->{__PACKAGE__.'clients'} = [],
  850.   $self->{__PACKAGE__.'active'} = '',
  851.   $self->_selector->add($listener);
  852.   return($self);
  853. }
  854.  
  855. sub _listener {
  856.   my $self = shift;
  857.   $self->{__PACKAGE__.'listener'} = shift if(@_);
  858.   return($self->{__PACKAGE__.'listener'});
  859. }
  860. sub _clients {
  861.   my $self = shift;
  862.   $self->{__PACKAGE__.'clients'} = shift if(@_);
  863.   return($self->{__PACKAGE__.'clients'});
  864. }
  865. sub _active {
  866.   my $self = shift;
  867.   $self->{__PACKAGE__.'active'} = shift if(@_);
  868.   return($self->{__PACKAGE__.'active'});
  869. }
  870.  
  871. sub getClients {
  872.   my $self = shift;
  873.   return(@{$self->_clients});
  874. }
  875.  
  876. sub addClient {
  877.   my $self = shift;
  878.   push(@{$self->_clients}, @_);
  879. }
  880.  
  881. sub removeClient {
  882.   my $self = shift;
  883.   my $client = shift;
  884.   for(my $i = 0; $i < @{$self->_clients}; $i++) {
  885.     splice(@{$self->_clients}, $i, 1) if($self->_clients->[$i] == $client);
  886.   }
  887.   $self->_selector->remove($client);
  888. }
  889.  
  890.  
  891. sub isClient {
  892.   my $self = shift;
  893.   my $socket = shift;
  894.   return(grep {$_ == $socket} $self->getClients);
  895. }
  896.  
  897. sub handleSocket {
  898.   my $self = shift;
  899.   my $socket = shift;
  900.   if($socket == $self->_listener) {
  901.     $self->handleListenListener($socket);
  902.   }
  903.   elsif($self->isClient($socket)) {
  904.     $self->handleListenClient($socket);
  905.   }
  906.   else {
  907.     $self->SUPER::handleSocket($socket);
  908.   }
  909. }
  910.  
  911. sub handleListenListener {
  912.   my $self = shift;
  913.   my $socket = shift;
  914.   my $newSock = $socket->accept;
  915.   $self->addClient($newSock);
  916.   $self->_selector->add($newSock);
  917. }
  918.  
  919. sub handleListenClient {
  920.   my $self = shift;
  921.   my $socket = shift;
  922.  
  923.   my $data;
  924.   $socket->recv($data, $recvLength);
  925.  
  926.   if(!length($data)) {
  927.     $self->removeClient($socket);
  928.     return;
  929.   }
  930.  
  931.   $self->_active($socket);
  932.   $self->handleData($data);
  933. }
  934.  
  935. sub cprint {
  936.   my $self = shift;
  937.   $self->_active->send(shift)  if($self->_active);
  938. }
  939.  
  940. sub message {
  941.   my $self = shift;
  942.   my $data = shift;
  943.   foreach ($self->getClients) {
  944.     $_->send("* $data\n");
  945.   }
  946. }
  947.  
  948.  
  949. #####        #####
  950. ##  SocketBase  ##
  951. #####        #####
  952. package sN::socketBase;
  953. use strict;
  954. use base 'IO::Socket::INET';
  955.  
  956. #sub new {
  957. #  my $className = shift;
  958. #  my $socket = shift;
  959. #  my $self = bless($socket, $className);
  960. #  return($self);
  961. #}
  962.  
  963. sub new {
  964.   my $class = shift;
  965.   my $glob = $class->SUPER::new(@_);
  966.   return if(!$glob);
  967.   my $self = *{$glob}{HASH};
  968.   $self->{__PACKAGE__.'name'} = '';
  969.   $self->{__PACKAGE__.'parent'} = '';
  970.   return($glob);
  971. }
  972.  
  973. sub _name {
  974.   my $glob = shift;
  975.   my $self = *{$glob}{HASH};
  976.   $self->{__PACKAGE__.'name'} = shift if(@_);
  977.   return($self->{__PACKAGE__.'name'});
  978. }
  979. sub _parent {
  980.   my $glob = shift;
  981.   my $self = *{$glob}{HASH};
  982.   $self->{__PACKAGE__.'parent'} = shift if(@_);
  983.   return($self->{__PACKAGE__.'parent'});
  984. }
  985.  
  986. sub getName {
  987.   my $self = shift;
  988.   return($self->_name);
  989. }
  990. sub getParent {
  991.   my $self = shift;
  992.   return($self->_parent);
  993. }
  994. sub setName {
  995.   my $self = shift;
  996.   return($self->_name(shift));
  997. }
  998. sub setParent {
  999.   my $self = shift;
  1000.   return($self->_parent(shift));
  1001. }
  1002.  
  1003. sub getSockets {
  1004.   my $self = shift;
  1005.   return($self);
  1006. }
  1007.  
  1008. sub destroySelf {
  1009.   my $self = shift;
  1010.   $self->shutdown(2);
  1011. }
  1012.  
  1013. sub isListener {
  1014.   return(0);
  1015. }
  1016.  
  1017. sub isServer {
  1018.   return(0);
  1019. }
  1020.  
  1021. sub isAttachedListener {
  1022.   return(0);
  1023. }
  1024.  
  1025. sub isClient {
  1026.   return(0);
  1027. }
  1028.  
  1029. #####      #####
  1030. ##  listener  ##
  1031. #####      #####
  1032. package sN::listener;
  1033. use strict;
  1034. use base 'sN::socketBase';
  1035.  
  1036. sub new {
  1037.   my $class = shift;
  1038.   my $glob = $class->SUPER::new(@_);
  1039.   return if(!$glob);
  1040.   my $self = *{$glob}{HASH};
  1041.   $self->{__PACKAGE__.'servers'} = [];
  1042.   return($glob);
  1043. }
  1044.  
  1045. sub _servers {
  1046.   my $glob = shift;
  1047.   my $self = *{$glob}{HASH};
  1048.   $self->{__PACKAGE__.'servers'} = shift if(@_);
  1049.   return($self->{__PACKAGE__.'servers'});
  1050. }
  1051.  
  1052. sub getServers {
  1053.   my $self = shift;
  1054.   return(@{$self->_servers});
  1055. }
  1056. sub addServer {
  1057.   my $self = shift;
  1058.   push(@{$self->_servers}, @_);
  1059.   foreach (@_) {
  1060.     $_->setParent($self);
  1061.   }
  1062. }
  1063. sub removeServer {
  1064.   my $self = shift;
  1065.   my $server = shift;
  1066.   for(my $i = 0; $i < @{$self->_servers}; $i++) {
  1067.     splice(@{$self->_servers}, $i, 1) if($self->_servers->[$i] == $server);
  1068.   }
  1069. }
  1070.  
  1071. sub getSockets {
  1072.   my $self = shift;
  1073.   my @sockets = $self->SUPER::getSockets;
  1074.   foreach($self->getServers) {
  1075.     push(@sockets, $_->getSockets);
  1076.   }
  1077.   return(@sockets);
  1078. }
  1079.  
  1080. sub destroySelf {
  1081.   my $self = shift;
  1082.   $self->getParent->removeListener($self);
  1083.   $self->SUPER::destroySelf;
  1084. }
  1085.  
  1086. sub isListener {
  1087.   return(1);
  1088. }
  1089.  
  1090. #####    #####
  1091. ##  server  ##
  1092. #####    #####
  1093. package sN::server;
  1094. use base 'sN::socketBase';
  1095.  
  1096. sub new {
  1097.   my $class = shift;
  1098.   my $glob = $class->SUPER::new(@_);
  1099.   return if(!$glob);
  1100.   my $self = *{$glob}{HASH};
  1101.   $self->{__PACKAGE__.'attachedListeners'} = [];
  1102.   $self->{__PACKAGE__.'bufferedData'} = '';
  1103.   return($glob);
  1104. }
  1105.  
  1106. sub _attachedListeners {
  1107.   my $glob = shift;
  1108.   my $self = *{$glob}{HASH};
  1109.   $self->{__PACKAGE__.'attachedListeners'} = shift if(@_);
  1110.   return($self->{__PACKAGE__.'attachedListeners'});
  1111. }
  1112.  
  1113. sub _bufferedData {
  1114.   my $glob = shift;
  1115.   my $self = *{$glob}{HASH};
  1116.   $self->{__PACKAGE__.'bufferedData'} = shift if(@_);
  1117.   return($self->{__PACKAGE__.'bufferedData'});
  1118. }
  1119.  
  1120. sub getAttachedListeners {
  1121.   my $self = shift;
  1122.   return(@{$self->_attachedListeners});
  1123. }
  1124. sub addAttachedListener {
  1125.   my $self = shift;
  1126.   push(@{$self->_attachedListeners}, @_);
  1127.   foreach (@_) {
  1128.     $_->setParent($self);
  1129.   }
  1130. }
  1131. sub removeAttachedListener {
  1132.   my $self = shift;
  1133.   my $attachedListener = shift;
  1134.   for(my $i = 0; $i < @{$self->_attachedListeners}; $i++) {
  1135.     splice(@{$self->_attachedListeners}, $i, 1) if($self->_attachedListeners->[$i] == $attachedListener);
  1136.   }
  1137. }
  1138.  
  1139. sub getClients {
  1140.   my $self = shift;
  1141.   my @clients;
  1142.   foreach ($self->getAttachedListeners) {
  1143.     push(@clients, $_->getClients);
  1144.   }
  1145.   return(@clients);
  1146. }
  1147.  
  1148. # Until I implement something with multiple servers, this will just tear down the object.
  1149. #fixme Need to figure this out more
  1150. sub removeServer {
  1151.   my $self = shift;
  1152.   $self->getParent->removeServer($self);
  1153.   $self->shutdown(2);
  1154. }
  1155.  
  1156. sub bufferData {
  1157.   my $self = shift;
  1158.   my $data = shift;
  1159.   $self->_bufferedData($self->_bufferedData . $data);
  1160. }
  1161.  
  1162. sub flushBuffer {
  1163.   my $self = shift;
  1164.   if($self->getClients && defined($self->_bufferedData)) {
  1165.     $self->writeClients($self->_bufferedData);
  1166.     $self->_bufferedData('');
  1167.   }
  1168. }
  1169.  
  1170. ###
  1171. # Write'ers
  1172. ###
  1173. sub serverWrite {
  1174.   my $self = shift;
  1175.   my $data = shift;
  1176.   if($self->getClients == 0) {
  1177. #fixme    print "No clients, buffering data\n" if($main::superDebug);
  1178. #fixme    print "Buffering data.\n";
  1179.     $self->bufferData($data);
  1180.   }
  1181.   else {
  1182. #fixme    print "Writing out data.\n" if($main::superDebug);
  1183.     $self->writeClients($data);
  1184.   }
  1185. }
  1186. sub clientWrite {
  1187.   my $self = shift;
  1188.   my $except = shift;
  1189.   my $data = shift;
  1190.   $self->writeServers($data);
  1191.   $self->writeClientsExcept($except, $data);
  1192. }
  1193. sub writeServers {
  1194.   my $self = shift;
  1195.   my $data = shift;
  1196.   $self->send($data);
  1197. }
  1198. sub writeClients {
  1199.   my $self = shift;
  1200.   my $data = shift;
  1201.   foreach my $client ($self->getClients) {
  1202.     $client->send($data);
  1203.   }
  1204. }
  1205. sub writeClientsExcept {
  1206.   my $self = shift;
  1207.   my $except = shift;
  1208.   my $data = shift;
  1209.   foreach my $listener ($self->getAttachedListeners) {
  1210.     foreach my $client ($listener->getClients) {
  1211.       next if($client == $except);
  1212.       $client->send($data);
  1213.     }
  1214.   }
  1215. }
  1216.  
  1217. sub getSockets {
  1218.   my $self = shift;
  1219.   my @sockets = $self->SUPER::getSockets;
  1220.   foreach($self->getAttachedListeners) {
  1221.     push(@sockets, $_->getSockets);
  1222.   }
  1223.   return(@sockets);
  1224. }
  1225. sub destroySelf {
  1226.   my $self = shift;
  1227.   $self->getParent->removeServer($self);
  1228.   $self->SUPER::destroySelf;
  1229. }
  1230. sub isServer {
  1231.   return(1);
  1232. }
  1233.  
  1234.  
  1235. #####              #####
  1236. ##  attachedListener  ##
  1237. #####              #####
  1238. package sN::attachedListener;
  1239. use base 'sN::socketBase';
  1240.  
  1241. sub new {
  1242.   my $class = shift;
  1243.   my $glob = $class->SUPER::new(@_);
  1244.   return if(!$glob);
  1245.   my $self = *{$glob}{HASH};
  1246.   $self->{__PACKAGE__.'clients'} = [];
  1247.   return($glob);
  1248. }
  1249.  
  1250. sub _clients {
  1251.   my $glob = shift;
  1252.   my $self = *{$glob}{HASH};
  1253.   $self->{__PACKAGE__.'clients'} = shift if(@_);
  1254.   return($self->{__PACKAGE__.'clients'});
  1255. }
  1256.  
  1257. sub getClients {
  1258.   my $self = shift;
  1259.   return(@{$self->_clients});
  1260. }
  1261. sub addClient {
  1262.   my $self = shift;
  1263.   push(@{$self->_clients}, @_);
  1264.   foreach (@_) {
  1265.     $_->setParent($self);
  1266.   }
  1267.   $self->getParent->flushBuffer;
  1268. }
  1269. sub removeClient {
  1270.   my $self = shift;
  1271.   my $client = shift;
  1272.   for(my $i = 0; $i < @{$self->_clients}; $i++) {
  1273.     splice(@{$self->_clients}, $i, 1) if($self->_clients->[$i] == $client);
  1274.   }
  1275. }
  1276.  
  1277.  
  1278. sub getSockets {
  1279.   my $self = shift;
  1280.   my @sockets = $self->SUPER::getSockets;
  1281.   foreach($self->getClients) {
  1282.     push(@sockets, $_->getSockets);
  1283.   }
  1284.   return(@sockets);
  1285. }
  1286. sub destroySelf {
  1287.   my $self = shift;
  1288.   $self->getParent->removeAttachedListener($self);
  1289.   $self->SUPER::destroySelf;
  1290. }
  1291.  
  1292. sub isAttachedListener {
  1293.   return(1);
  1294. }
  1295.  
  1296.  
  1297. #####    #####
  1298. ##  client  ##
  1299. #####    #####
  1300. package sN::client;
  1301. use base 'sN::socketBase';
  1302.  
  1303. sub destroySelf {
  1304.   my $self = shift;
  1305.   $self->getParent->removeClient($self);
  1306.   $self->SUPER::destroySelf;
  1307. }
  1308.  
  1309. sub isClient {
  1310.   return(1);
  1311. }
  1312.  
  1313.  
  1314. #####     #####
  1315. ## Col Print ##
  1316. #####     #####
  1317. package sN::colprint;
  1318. use strict;
  1319.  
  1320. sub new {
  1321.   return(bless(
  1322.     {
  1323.       __PACKAGE__.'data' => [],
  1324.       __PACKAGE__.'maxLen' => [],
  1325.       __PACKAGE__.'initIndent' => $_[1] || 0,
  1326.       __PACKAGE__.'pad' => $_[2] || 2,
  1327.     }, shift)
  1328.   );
  1329. }
  1330.  
  1331. ###
  1332. # Internals
  1333. ###
  1334. sub _data {
  1335.   my $self = shift;
  1336.   $self->{__PACKAGE__.'data'} = shift if(@_);
  1337.   return($self->{__PACKAGE__.'data'});
  1338. }
  1339. sub _maxLen {
  1340.   my $self = shift;
  1341.   $self->{__PACKAGE__.'maxLen'} = shift if(@_);
  1342.   return($self->{__PACKAGE__.'maxLen'});
  1343. }
  1344. sub _initIndent {
  1345.   my $self = shift;
  1346.   $self->{__PACKAGE__.'initIndent'} = shift if(@_);
  1347.   return($self->{__PACKAGE__.'initIndent'});
  1348. }
  1349. sub _pad {
  1350.   my $self = shift;
  1351.   $self->{__PACKAGE__.'pad'} = shift if(@_);
  1352.   return($self->{__PACKAGE__.'pad'});
  1353. }
  1354.  
  1355.  
  1356. ###
  1357. # Add'ers
  1358. ###
  1359. sub addRow {
  1360.   my $self = shift;
  1361.   my $maxLen = $self->_maxLen;
  1362.   push(@{$self->_data}, [ @_ ]);
  1363.   for(my $i = 0; $i < @_; $i++) {
  1364.     $maxLen->[$i] = length($_[$i]) if(length($_[$i]) > $maxLen->[$i]);
  1365.   }
  1366. }
  1367.  
  1368. ###
  1369. # Get'ers
  1370. ###
  1371. sub getOutput {
  1372.   my $self = shift;
  1373.   my $output;
  1374.   foreach (@{$self->_data}) {
  1375.     $output .= " " x ($self->_pad * $self->_initIndent);
  1376.     for(my $i = 0; $i < @{$_}; $i++) {
  1377.       my $cell = $_->[$i];
  1378.       if($cell eq '__hr__') {
  1379.         $output .= "-" x $self->_maxLen->[$i] . " " x $self->_pad;
  1380.         next;
  1381.       }
  1382.       $output .= $cell . " " x ($self->_maxLen->[$i] - length($cell) + $self->_pad);
  1383.     }
  1384.     $output .= "\n";
  1385.   }
  1386.   return($output);
  1387. }
  1388.